package pers.bc.utils.file;

import java.io.File;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.Writer;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.log4j.FileAppender;
import org.apache.log4j.Layout;
import org.apache.log4j.helpers.CountingQuietWriter;
import org.apache.log4j.helpers.LogLog;
import org.apache.log4j.helpers.OptionConverter;
import org.apache.log4j.helpers.QuietWriter;
import org.apache.log4j.spi.LoggingEvent;

public class RollingFileAppenderBc extends FileAppender
{
    protected long maxFileSize;
    protected int maxBackupIndex;
    private long nextRollover;

    public RollingFileAppenderBc() {
        this.maxFileSize = 10485760L;
        this.maxBackupIndex = 1;
        this.nextRollover = 0L;
    }

    public RollingFileAppenderBc(final Layout layout, final String filename, final boolean append) throws IOException {
        super(layout, filename, append);
        this.maxFileSize = 10485760L;
        this.maxBackupIndex = 1;
        this.nextRollover = 0L;
    }

    public RollingFileAppenderBc(final Layout layout, final String filename) throws IOException {
        super(layout, filename);
        this.maxFileSize = 10485760L;
        this.maxBackupIndex = 1;
        this.nextRollover = 0L;
    }

    public int getMaxBackupIndex() {
        return this.maxBackupIndex;
    }

    public long getMaximumFileSize() {
        return this.maxFileSize;
    }

    public void rollOver() {
        if (this.qw != null) {
            final long size = ((CountingQuietWriter) this.qw).getCount();
            LogLog.debug("rolling over count=" + size);
            this.nextRollover = size + this.maxFileSize;
        }
        LogLog.debug("maxBackupIndex=" + this.maxBackupIndex);
        boolean renameSucceeded = true;
        if (this.maxBackupIndex > 0) {
            int ii = 0;
            String newFilePath = null;
            File newFile = null;
            File oldFile =  new File(fileName);
            String fileName = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
            String[] split = this.fileName.split("\\.");
            String prefix = split[0] + fileName;
            String suffix = split[1];
            do
            {
                newFilePath = prefix + " {" + ii + "}." + suffix;
                newFile = new File(newFilePath);
                ii++;
            }
            while (newFile.exists()); 

            closeFile();
            renameSucceeded = oldFile.renameTo(newFile); 

//            ii = 0;
//            do
//            {
//                closeFile();
//                renameSucceeded = oldFile.renameTo(newFile); 
//                ii++;
//            }
//            while (!renameSucceeded||ii==10000);

            System.err.println("rollOver经过【"+ii+"】次修改成功！！");
            if (renameSucceeded) {
                final File target = new File(prefix + " {" + 1 + "}." + suffix);
                this.closeFile();
                File file = new File(this.fileName);
                LogLog.debug("Renaming file " + file + " to " + target);
                renameSucceeded = file.renameTo(target);
                if (!renameSucceeded) {
                    try {
                        this.setFile(this.fileName, true, this.bufferedIO, this.bufferSize);
                    } catch (final IOException e) {
                        if (e instanceof InterruptedIOException) {
                            Thread.currentThread().interrupt();
                        }
                        LogLog.error("setFile(" + this.fileName + ", true) call failed.", (Throwable) e);
                    }
                }
            }
        }
//        if (renameSucceeded) {
            try {
                this.setFile(this.fileName, false, this.bufferedIO, this.bufferSize);
                this.nextRollover = 0L;
            } catch (final IOException e) {
                if (e instanceof InterruptedIOException) {
                    Thread.currentThread().interrupt();
                }
                LogLog.error("setFile(" + this.fileName + ", false) call failed.", (Throwable) e);
            }
//        }
    }
    protected void closeFile() {
        if (this.qw != null) {
            try {
                this.qw.close();
            } catch (final IOException e) {
                if (e instanceof InterruptedIOException) {
                    Thread.currentThread().interrupt();
                }
                LogLog.error("Could not close " + this.qw, (Throwable) e);
            }
        }
    }
    
    public synchronized void setFile(final String fileName, final boolean append, final boolean bufferedIO,
            final int bufferSize) throws IOException {
        super.setFile(fileName, append, this.bufferedIO, this.bufferSize);
        if (append) {
            final File f = new File(fileName);
            ((CountingQuietWriter) this.qw).setCount(f.length());
        }
    }

    public void setMaxBackupIndex(final int maxBackups) {
        this.maxBackupIndex = maxBackups;
    }

    public void setMaximumFileSize(final long maxFileSize) {
        this.maxFileSize = maxFileSize;
    }

    public void setMaxFileSize(final String value) {
        this.maxFileSize = OptionConverter.toFileSize(value, this.maxFileSize + 1L);
    }

    protected void setQWForFiles(final Writer writer) {
        this.qw = (QuietWriter) new CountingQuietWriter(writer, this.errorHandler);
    }

    protected void subAppend(final LoggingEvent event) {
        super.subAppend(event);
        if (this.fileName != null && this.qw != null) {
            final long size = ((CountingQuietWriter) this.qw).getCount();
            if (size >= this.maxFileSize && size >= this.nextRollover) {
                this.rollOver();
            }
        }
    }
}
